using System;
using System.Collections.Generic;
using System.Numerics;
using TTEngine.Graphics;
using TTEngine.TTMath;
using Silk.NET.OpenGLES;
using TTEngine.Resource;
namespace TTEngine.Graphics
{
    // TODO: 需要以下类型:
    // - ElementFormat
    // - ElementSprite 
    // - TextureFormat
    // - MaxRectsBin
    // - SpriteData

    public class PackTexture : ResourceObj
    {
        private MaxRectsBin _packer;
        private bool _dirty;
        private byte _curLayer;
        private ImageData _pixelBuf;
        Texture2DArray _texture;
        public uint Width => _texture.Width;
        public uint Height => _texture.Height;
        public byte LayerCount => _texture.LayerCount;
        public Texture2DArray Texture => _texture;
        protected override void OnDestory()
        {
            _texture.DecRef();
            if (_texture.CanDispose)
            {
                _texture.Destory();
            }
        }

        public PackTexture(ResourcePackage package, uint width, uint height, byte layercount, TextureType format)
            : base(package)
        {
            _curLayer = 0;
            _packer = new MaxRectsBin((int)width, (int)height);
            _dirty = false;
            _pixelBuf = new ImageData(width, height, (format == TextureType.RGBA_32) ? ImageFormat.RGBA : ImageFormat.Gray);
            _texture = new Texture2DArray(package, width, height, layercount, format);
        }

        public PackedTextureElement AddSprite(SpriteData data, SpriteEffect effect, Border border)
        {
            var rect = _packer.Add(new SizeRect((int)data.Width + border.left + border.right, (int)data.Height + border.top + border.bottom));
            if (rect == null)
            {
                _packer.Reset();
                rect = _packer.Add(new SizeRect((int)data.Width + border.left + border.right, (int)data.Height + border.top + border.bottom));
                Apply();
                _curLayer++;
                if (_curLayer >= this._texture.LayerCount)
                    throw new Exception("AddSprite:Layer 满了");
            }
            data.CopyTo(_pixelBuf, rect.Value.X + border.left, rect.Value.Y + border.top);
            // for (int y = 0; y < data.Height; y++)
            // {
            //     for (int x = 0; x < data.Width; x++)
            //     {
            //         int index = ((y + rect.Value.Y) * Width + (rect.Value.X + x));
            //         if (this.format == TextureType.RGBA_32)
            //         {
            //             data.CopyTo(_pixelBuf, index * 4, TextureType.RGBA_32, x, y);
            //         }
            //         else
            //         {
            //             data.CopyPixel(_pixelBuf, index, TextureType.R8, x, y);
            //         }
            //     }
            // }
            _dirty = true;

            var s = new PackedTextureElement();
            s.sizeTL = new Vector2I(-data.PivotX, -data.PivotY);
            s.sizeRB = new Vector2I((int)data.Width - data.PivotX, (int)data.Height - data.PivotY);

            float u1 = (rect.Value.X + border.left) / (float)this._texture.Width;
            float v1 = (rect.Value.Y + border.top) / (float)_texture.Height;
            float u2 = (rect.Value.X + data.Width - border.right) / (float)_texture.Width;
            float v2 = (rect.Value.Y + data.Height - border.bottom) / (float)_texture.Height;

            s.uvCenter = new Vector2((u1 + u2) * 0.5f, (v1 + v2) * 0.5f);
            s.uvHalfSize = new Vector2((u2 - u1) * 0.5f, (v2 - v1) * 0.5f);
            s.uvLayer = _curLayer;
            s.eff = effect;

            return s;
        }

        public void Apply(bool force = false)
        {
            if (_dirty || force)
            {
                _texture.UploadImageData(_curLayer, 0, 0, _texture.Width, _texture.Height, _pixelBuf);
                _dirty = false;
            }
        }
    }
}